#include <Utils/Type.h>
#include "HalAlgRSA.h"
#include "HalAlgGloBuff.h"
#include "string.h"
#include "../alg_pr/ALGRsa_PR.h"


static UINT8 TestCRTMode(UINT8* pBuf,UINT32 nLen)
{
	UINT32 i;
	for(i = 0 ;i<nLen;i++)
	{
		if(pBuf[i])
			return(pBuf[i]);
	}
	return (0);
}

UINT32 HalAlgRSA_Init(UINT16 BitLen)
{
	RsaKeyPair *pRSAKey;

	if(BitLen != 1024 && BitLen != 2048)
	{
        return RT_FAIL;
	}
	
	pRSAKey = (RsaKeyPair*)GetAlgRSAContextBuff();
	pRSAKey->BitLen = BitLen;
	ALGRsa_PR_Rsa_Init();
	return RT_OK;		
}

UINT32 HalAlgRSA_GenKeyPair(UINT32 Exp)
{
	R_RSA_KEYPAIR RsaKey;
	R_RSA_PROTO_KEY ProtoKey;

	RsaKeyPair *pRSAKey;
	UINT32 nPairOffset;
	UINT32 nRet;  
	
	pRSAKey = (RsaKeyPair*)GetAlgRSAContextBuff();

	ProtoKey.PublicExponent = Exp; 
	ProtoKey.bits = pRSAKey->BitLen; 

	nPairOffset = MAX_RSA_MODULUS_LEN - ProtoKey.bits / 8;
    
	RsaKey.bits = (UINT16)pRSAKey->BitLen;
	RsaKey.modulus = (UINT32*)(pRSAKey->Modulus + nPairOffset);
	RsaKey.publicExponent = (UINT32*)(pRSAKey->PublicExponent + 252);
	RsaKey.exponent = (UINT32*)(pRSAKey->Exponent + nPairOffset);
	RsaKey.coefficient = (UINT32*)(pRSAKey->Coefficient + nPairOffset / 2);
	RsaKey.prime[0] = (UINT32*)(pRSAKey->Prime1 + nPairOffset / 2);
	RsaKey.prime[1] = (UINT32*)(pRSAKey->Prime2 + nPairOffset / 2);
	RsaKey.primeExponent[0] = (UINT32*)(pRSAKey->Prime1Exponent + nPairOffset / 2);
	RsaKey.primeExponent[1] = (UINT32*)(pRSAKey->Prime2Exponent + nPairOffset / 2);
		
    nRet = ALGRsa_PR_GenKeyPair(ProtoKey, &RsaKey);

	return nRet;
}

UINT32 HalAlgRSA_Public_Update(UINT8 *pInBuf, UINT32 nLen, UINT8 *pOutBuf)
{
	R_RSA_PUBLIC_KEY RsaKey;
	RsaKeyPair *pRSAKey;
	UINT32 nPairOffset;
	UINT32 rLen;
	UINT32 nRet;
	
	pRSAKey = (RsaKeyPair*)GetAlgRSAContextBuff();
	
	if(pInBuf == NULL)
	{
		return 1;
	}
	
	if(nLen != pRSAKey->BitLen / 8)
	{
		return 2;
	}

	nPairOffset = MAX_RSA_MODULUS_LEN - nLen;
	
	RsaKey.bits  = (UINT16)pRSAKey->BitLen;	
				
	RsaKey.modulus = (UINT32*)(pRSAKey->Modulus + nPairOffset);
	RsaKey.publicExponent = (UINT32*)(pRSAKey->PublicExponent + 252);
	//memset((UINT8*)pRSAKey->PublicExponent, 0,252);
	nRet = ALGRsa_PR_PubKeyOpt(pOutBuf, &rLen, pInBuf, nLen, &RsaKey);

	return nRet;
}

UINT32 HalAlgRSA_Private_Update(UINT8 *pInBuf, UINT32 nLen, UINT8 *pOutBuf)
{
	R_RSA_KEYPAIR RsaKey;
	RsaKeyPair *pRSAKey;
	UINT32 nPairOffset;
	UINT32 rLen ;
	UINT32 nRet; 

	pRSAKey = (RsaKeyPair*)GetAlgRSAContextBuff();
	
	if(pInBuf == NULL)
	{
		return 1;
	}

	if(nLen != pRSAKey->BitLen / 8)
	{
		return 2;
	}

	nPairOffset = MAX_RSA_MODULUS_LEN - nLen;

	RsaKey.bits  = (UINT16)pRSAKey->BitLen;	

	RsaKey.modulus = (UINT32*)(pRSAKey->Modulus + nPairOffset);
	RsaKey.exponent = (UINT32*)(pRSAKey->Exponent + nPairOffset);
    RsaKey.coefficient = (UINT32*)(pRSAKey->Coefficient + nPairOffset / 2);
	RsaKey.prime[0] = (UINT32*)(pRSAKey->Prime1 + nPairOffset / 2);
	RsaKey.prime[1] = (UINT32*)(pRSAKey->Prime2 + nPairOffset / 2);
	RsaKey.primeExponent[0] = (UINT32*)(pRSAKey->Prime1Exponent + nPairOffset / 2);
	RsaKey.primeExponent[1] = (UINT32*)(pRSAKey->Prime2Exponent + nPairOffset / 2);

	if(TestCRTMode((UINT8*)RsaKey.coefficient, nLen / 2))
	{
	 	nRet = ALGRsa_PR_PriKeyOpt(pOutBuf, &rLen, pInBuf, nLen, &RsaKey);	
	} 
	else
	{
		nRet = ALGRsa_PR_PriKeyOpt_NoCRT(pOutBuf, &rLen, pInBuf, nLen, &RsaKey);
	}
	
	return nRet;
}

UINT32 HalAlgRSA_Final()
{
    return (0);
}

void *HalAlgRSA_GetKeyPairContext(UINT16 *pLen)
{
	if(pLen != NULL)
	{
		*pLen = sizeof(RsaKeyPair);
	}

	return (void*)GetAlgRSAContextBuff();
}
